import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;
import com.pavisoft.irecipe.*;
import java.net.URL;

public class RecipeWindowController extends NSWindowController {

    public NSTextView directions; /* IBOutlet */
    public NSTableView ingredients; /* IBOutlet */
    public NSTextField name; /* IBOutlet */
    public Recipe recipe; /* IBOutlet */
    public NSWindow nswindow; /* IBOutlet */
    public NSTableView keywords;
    public NSTextField yield;
    public NSTextField preptime;
    public NSTextField comments;
    
    private NSTableView recipeViewer;
    private RecipeLibrary library;
    
    NameFieldDelegate nameDelegate;
    DirectionsDelegate dirDelegate;
    IngredientsDelegate ingDelegate;
    IngredientsDataSource ingDS;
    KeywordsDataSource kwDS;
    KeywordsDelegate kwDelegate;
    YieldDelegate yieldDelegate;
    PreptimeDelegate preptimeDelegate;
    CommentsDelegate commentsDelegate;
    NSMutableArray dsArr; // crazy but necessary to prevent premature garbage collection
    NSMutableArray delegateArr;
    
    private final String INGREDIENTS_PBOARD_TYPE = "iRecipe!INGREDIENT";
    
    NSArray ingDragTypes;

    /** Creates a new <code>RecipeWindowController</code> associated with the
     *  given <code>Recipe</code> <code>recipe</code>. The library must also be
     *  passed so it can be saved when needed; and the object (NSTableViewer
     *  in the current implementation) representing the list of recipes must also
     *  be passed so that it can be refreshed when needed. (There might be a better way
     *  to do this, but it works.)
     */
    public RecipeWindowController(Recipe recipe, RecipeLibrary library, NSTableView recipeViewer) {
        super("RecipeWindow"); // load from RecipeWindow.nib file
        this.recipe = recipe;
        this.library = library;
        this.recipeViewer = recipeViewer;
        
        ingDragTypes = new NSArray(INGREDIENTS_PBOARD_TYPE);
        
        nameDelegate = new NameFieldDelegate();
        dirDelegate = new DirectionsDelegate();
        ingDelegate = new IngredientsDelegate();
        kwDS = new KeywordsDataSource();
        kwDelegate = new KeywordsDelegate();
        yieldDelegate = new YieldDelegate();
        preptimeDelegate = new PreptimeDelegate();
        commentsDelegate = new CommentsDelegate();
        ingDS = new IngredientsDataSource();
        dsArr = new NSMutableArray(new Object[] { ingDS, kwDS });
        delegateArr = new NSMutableArray(new Object[] { nameDelegate, 
            ingDelegate, dirDelegate, kwDelegate, yieldDelegate,
            preptimeDelegate, commentsDelegate });
    }
    
    private void initWindow()
    {
        this.directions.setDelegate(delegateArr.objectAtIndex(2));
        this.ingredients.setDelegate(delegateArr.objectAtIndex(1));
        this.ingredients.setDataSource(dsArr.objectAtIndex(0));
        this.name.setDelegate(delegateArr.objectAtIndex(0));
        this.keywords.setDataSource(dsArr.objectAtIndex(1));
        this.keywords.setDelegate(delegateArr.objectAtIndex(3));
        this.yield.setDelegate(delegateArr.objectAtIndex(4));
        this.preptime.setDelegate(delegateArr.objectAtIndex(5));
        this.comments.setDelegate(delegateArr.objectAtIndex(6));
        
        ingredients.registerForDraggedTypes(ingDragTypes);
        
        if (recipe.getName() != null)
        {
            this.name.setStringValue(recipe.getName());
            nswindow.setTitle(recipe.getName());
        }
        if (recipe.getDirections() != null)
            this.directions.setString(recipe.getDirections());
        if (recipe.getYield() != null)
            this.yield.setStringValue(recipe.getYield());
        if (recipe.getPrepTime() != null)
            this.preptime.setStringValue(recipe.getPrepTime());
        if (recipe.getDescription() != null)
            this.comments.setStringValue(recipe.getDescription());
    }

    public void showWindow(Object object)
    {
        super.showWindow(object);
        nswindow.makeKeyAndOrderFront(this);
        this.initWindow();
    }
    
    public void delIngredient(Object sender) { /* IBAction */
        int idx = ingredients.selectedRow();
        System.out.println("Del row " + idx);
        if (idx < recipe.getNumberOfIngredients())
        {
            recipe.removeIngredient(idx);
        }
        ingredients.reloadData();
    }

    public void newIngredient(Object sender) { /* IBAction */
        recipe.addIngredient(new Ingredient("New Ingredient"));
        recipe.getIngredient(recipe.getNumberOfIngredients() - 1).toString();
        this.ingredients.reloadData();
        this.ingredients.selectRow(ingredients.numberOfRows() - 1, false);
        this.ingredients.editLocation(0, ingredients.numberOfRows() -1, null, true);
    }

    public boolean windowShouldClose(Object object)
    {
        System.out.println("WindowShouldClose");
        library.saveLibrary();
        recipeViewer.reloadData();
        return true;
    }

    private boolean hasIngredients()
    {
        boolean has = true;
        if (recipe.getNumberOfIngredients() <= 0)
        {
            has = false;
        }
        return has;
    }
    
    public void keywordBtnClicked(NSObject sender)
    {
        String keyword = library.getKeywords()[keywords.clickedRow()];
        if (recipe.hasKeyword(keyword))
        {
            recipe.removeKeyword(keyword);
        }
        else
        {
            recipe.addKeyword(keyword);
        }
    }
    
    public boolean validateMenuItem(NSMenuItem menuItem)
    {
        if (menuItem.equals(AppController.mnuShowHideDrawer))
        {
            return true;
        }
        return false;
    }
    
    public void toggleInfoDrawer(NSObject sender)
    {
        NSDrawer d = (NSDrawer)nswindow.drawers().objectAtIndex(0);
        d.toggle(this);
    }

    class NameFieldDelegate
    {
        private boolean changed = false;

        public void controlTextDidBeginEditing(NSNotification n)
        {
            changed = false;
        }

        public void controlTextDidChange(NSNotification n)
        {
            changed = true;
        }
        
        public void controlTextDidEndEditing(NSNotification n)
        {
            if (changed)
            {
                recipe.setName(name.stringValue());          
                nswindow.setTitle(name.stringValue());
            }
            changed = false;
        }    
    }
    
    class YieldDelegate
    {
        private boolean changed = false;

        public void controlTextDidBeginEditing(NSNotification n)
        {
            changed = false;
        }

        public void controlTextDidChange(NSNotification n)
        {
            changed = true;
        }
        
        public void controlTextDidEndEditing(NSNotification n)
        {
            if (changed)
            {
                recipe.setYield(yield.stringValue());
            }
            changed = false;
        }    
    }
    
    class PreptimeDelegate
    {
        private boolean changed = false;

        public void controlTextDidBeginEditing(NSNotification n)
        {
            changed = false;
        }

        public void controlTextDidChange(NSNotification n)
        {
            changed = true;
        }
        
        public void controlTextDidEndEditing(NSNotification n)
        {
            if (changed)
            {
                recipe.setPrepTime(preptime.stringValue());
            }
            changed = false;
        }    
    }
    
    class DirectionsDelegate
    {
        private boolean changed = false;
        
        public void textDidBeginEditing(NSNotification n)
        {
            changed = false;
        }

        public void textDidChange(NSNotification n)
        {
            changed = true;
        }
        
        public void textDidEndEditing(NSNotification n)
        {
            if (changed)
            {
                recipe.setDirections(directions.string());
            }
            changed = false;
        }      
    }
    
    class CommentsDelegate
    {
        private boolean changed = false;
        
        public void controlTextDidBeginEditing(NSNotification n)
        {
            changed = false;
        }

        public void controlTextDidChange(NSNotification n)
        {
            changed = true;
        }
        
        public void controlTextDidEndEditing(NSNotification n)
        {
            if (changed)
            {
                recipe.setDescription(comments.stringValue());
            }
            changed = false;
        }      
    }
    
    class IngredientsDelegate
    {
//        public boolean tableViewShouldEditLocation(NSTableView nSTableView, NSTableColumn nSTableColumn, int i)
//        {
//        }
//
//        public boolean tableViewShouldSelectRow(NSTableView nSTableView, int i)
//        {
//        }     

    }
    
    class IngredientsDataSource
    {
        public int numberOfRowsInTableView(NSTableView nSTableView)
        {
            int size;
            size = recipe.getNumberOfIngredients();
            if (size == 0)
            {
                // Make room for "Add ingredient [-][+]" row if nothing is there
                size = 1;
            }
            return size;
        }

        public Object tableViewObjectValueForLocation(NSTableView nSTableView, NSTableColumn nSTableColumn, int i)
        {
            if (!(nSTableColumn.equals(ingredients.tableColumns().objectAtIndex(0)))) return null;
            
            String str = null;
            
            if (hasIngredients())
            {
                    str = recipe.getIngredient(i).toString();
            }
            else
            {
                str = null;
            }
            return str;
        }

        public void tableViewSetObjectValueForLocation(NSTableView nSTableView, Object object, NSTableColumn nSTableColumn, int i)
        {
            if (!(nSTableColumn.equals(nSTableView.tableColumns().objectAtIndex(0)))) return;
            
            if (!(hasIngredients()))
            {
                recipe.addIngredient(Ingredient.parseIngredient(object.toString(), true));
            }
            else
            {
                recipe.setIngredient(i, Ingredient.parseIngredient(object.toString(), true));
            }
        }
        
        // TODO: Change to version that uses NSIndexSet instead of NSArray (former is deprecated)
        public boolean tableViewWriteRowsToPasteboard(NSTableView tableView,
                NSArray rows, NSPasteboard pboard)
        {
            if (ingredients.numberOfRows() <= 1) return false;
            pboard.declareTypes(new NSArray(INGREDIENTS_PBOARD_TYPE), this);
            pboard.setDataForType(NSKeyedArchiver.archivedDataWithRootObject(rows),
                    INGREDIENTS_PBOARD_TYPE);
            return true;
        }
        
        public int tableViewValidateDrop(NSTableView tableView,
                NSDraggingInfo info, int row, int operation)
        {            
            if (operation == NSTableView.DropOn)
            {
                return NSDraggingInfo.DragOperationNone;
            }
//            if (tableView != ingredients) //needs work--see below
//            {
//                return NSDraggingInfo.DragOperationCopy;
//            }
            return NSDraggingInfo.DragOperationMove;
        }
        
        public boolean tableViewAcceptDrop(NSTableView tableView,
                NSDraggingInfo info, int row, int operation)
        {
            NSData data = info.draggingPasteboard().dataForType(INGREDIENTS_PBOARD_TYPE);
            Object obj = NSKeyedUnarchiver.unarchiveObjectWithData(data);
            NSMutableArray rows = (NSMutableArray)obj;
            if (tableView == ingredients) //akk, doesn't really detect if it was the tableview on THIS window ... see if can improve
            {
                recipe.moveIngredient(Integer.parseInt(rows.objectAtIndex(0).toString()), row);
            }
//            else  // came from different NSTableView (copying from another recipe) -- needs work to make work (how to access other recipe's ingredients)
//            {
//                recipe.addIngredient((Ingredient)recipe.getIngredient(Integer.parseInt(rows.objectAtIndex(0).toString())).clone(), row);
//            }
            ingredients.reloadData();
            return true;
        }

    }
    
    class KeywordsDataSource
    {
        public int numberOfRowsInTableView(NSTableView tv)
        {
            return library.getKeywords().length;
        }
//
//        public Object tableViewObjectValueForLocation(NSTableView tv, NSTableColumn col, int row)
//        { 
//            Object obj = null;
//            //if (col.equals(tv.tableColumns().objectAtIndex(0)))
//            {
//                obj = library.getKeywords()[row];
//                obj = "Test!";
//            }
//            return obj;
//        }

        public void tableViewSetObjectValueForLocation(NSTableView tv, Object obj, NSTableColumn col, int row)
        {
        }        
    }
    
    class KeywordsDelegate
    {
        public void tableViewWillDisplayCell(NSTableView tv, Object aCell, NSTableColumn col, int row)
        {
            if (aCell instanceof NSButtonCell)
            {
                NSButtonCell b = (NSButtonCell)aCell;
                b.setTitle(library.getKeywords()[row]);
                b.setAction(new NSSelector("keywordBtnClicked", new Class[] { Object.class }));
                b.setState(recipe.hasKeyword(library.getKeywords()[row]) ? 1 : 0);
            }
        }        
    }
}
